package gov.nasa.anml.lifted;

import java.util.ArrayList;
import java.util.List;

import gov.nasa.anml.PDDL;
import gov.nasa.anml.PDDL.Action;
import gov.nasa.anml.PDDL.ComplexAction;
import gov.nasa.anml.PDDL.FloatExpression;
import gov.nasa.anml.PDDL.FloatLiteral;
import gov.nasa.anml.utility.*;


public class Domain extends Unit<SimpleBoolean,SimpleVoid>  {

	public static final SimpleString defaultName = new SimpleString("TheDomain");
	public Domain() {super(null,defaultName);_Domain_init();}
	public Domain(SimpleString n) {super(null,n);_Domain_init();}
	public Domain(Scope parent) {super(parent,defaultName);_Domain_init();}
	public Domain(Scope parent, SimpleString n) {super(parent,n);_Domain_init();}
	protected final void _Domain_init() {
		types.put(objectType);
		types.put(symbolType);
		types.put(booleanType);
		types.put(integerType);
		types.put(stringType);
		types.put(floatType);

		// if we do want to give an absolute deadline on all activity then we need to avoid setting duration.init to a parameter;
		// instead duration.value has to be set to something.
		duration.init = new Parameter<SimpleFloat>(IntervalImp.durationName,floatType);
		start.value = ANMLFloat.ZeroF;
		end.init = duration.init;
		
		labels.put(this);
	}


	public Type<?> getType(TypeCode builtin) {
		return types.get(builtin.name);
//		switch(builtin) {
//		case Boolean:
//			return booleanType;
//		case Integer:
//			return integerType;
//		case String:
//			return stringType;
//		case Float:
//			return floatType;
//		case Object:
//			return objectType;
//		case Symbol:
//			return symbolType;
//		default:
//			System.err.println("Undefined type");
//			return null;
//		}
	}
	
	public IdentifierCode idCode() {
		return IdentifierCode.Domain;
	}

	public TypeCode typeCode() {
		return TypeCode.String;
	}


	// very, very, close to Unit.translateDecl()
	public void translate(PDDL pddl) {
		pddl.name = name.toString();
		
		if (duration.init instanceof Parameter || (duration.init == null && duration.value == null)) {
			asPDDLAction = pddl.new ComplexAction(pddl.name);
		} else {
			asPDDLAction = pddl.new Action(pddl.name);
			if(duration.init != null) {
				asPDDLAction.duration = (PDDL.FloatExpression) duration.init.translateExpr(pddl,this);
			} else {
				asPDDLAction.duration = pddl.new FloatLiteral(duration.value.v);
			}
		}

		pddl.actions.add(asPDDLAction);
		
		// should do nothing
		for (PDDL.Parameter p : pddl.context) {
			asPDDLAction.context.add(p);
		}
		
		int s = pddl.context.size();
		
		// also shouldn't be doing anything
		for (Parameter<? extends SimpleObject<?>> p : parameters.table) {
			p.translateDecl(pddl,this);
			if (p.asPDDLParameter() != null) 
				pddl.context.add(p.asPDDLParameter());
		}
		
		++pddl.depth;
		
		// the better technique does
		// s: +alive
		// o: ?true
		// e: -alive, -true
		// ...fix it later.
		ArrayList<PDDL.BooleanExpression> conditions = this.getPDDLConditions();
		ArrayList<PDDL.Effect> effects = this.getPDDLEffects();
//		conditions.add(pddl.wrap(PDDL.Time.Start,pddl.FalseRef));
//		effects.add(pddl.makeEffect(PDDL.Time.Start,pddl.TrueRef,true));
//		conditions.add(pddl.wrap(PDDL.Time.Interim,pddl.TrueRef));
//		conditions.add(pddl.TrueCondition);  // same as above line
//		effects.add(pddl.makeEffect(PDDL.Time.End,pddl.TrueRef,false));

		conditions.add(pddl.wrap(PDDL.Time.Interim,pddl.AliveRef));
		effects.add(pddl.makeEffect(PDDL.Time.End,pddl.AliveRef,false));
				
		_translateDecl(pddl,this);
		_translateStmt(pddl,this,PDDL.Time.Timeless); // only safe because the Domain is uber-global.
		
		int l = pddl.context.size() - s;
		while (--l >= 0)
			pddl.context.remove(s);
		
		--pddl.depth;
	}

}
